#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>


#define DTB_LEDNAME "XYT_DTBLED"
#define DTB_LEDCNT   1
#define LED_ON 0
#define LED_OFF 1
static void __iomem *IMX6U_CCM_CCR1;
static void __iomem *SW_MUX;
static void __iomem *SW_PAD;
static void __iomem *GPIO1_DR;
static void __iomem *GPID1_GDIR;
static u32 regdate[10];
//设备结构体
struct dts_led
{
    dev_t   devid ;
    int major;
    struct cdev cdev;  
    int minjor;
    struct class *class; //自dong创建设备节点
    struct device *device;//设备
    struct device_node *nd; //设备节点
};

static struct dts_led dtsled;

void LED_Staus(int staus)
{
    int val = 0;
    if (staus == LED_ON)
    {
        val = readl(GPIO1_DR);
        val &= ~(1 << 4);
        writel(val, GPIO1_DR);
        printk("LEDON\n");
    }
    else
    {
        val = readl(GPIO1_DR);
        val |= (1 << 4);
        writel(val, GPIO1_DR);
        printk("LEDOFF\n");
    }
}

static int LED_open(struct inode *inode, struct file *fs)
{
    fs->private_data = &dtsled;
    return 0;
}

static int LED_release(struct inode *inode, struct file *fs)
{

    return 0;
}
static ssize_t LED_read(struct file *fs, char __user *buff, size_t count, loff_t *loff)
{

    return count;
}
static ssize_t LED_write(struct file *fs, const char __user *buff, size_t count, loff_t *opps)
{
    u8 ret =0;
    char Tbuff[100] ={"      "}; 
    ret = copy_from_user(Tbuff,buff,count);
    if(ret < 0)
    {
        printk("write erro\n");
        return -EIO;
    }
    else 
    {
        printk("Tbuff = %s\n",Tbuff);
        if(Tbuff[0] == '0')
        {
            LED_Staus(LED_ON);
        }
        else 
        {
            LED_Staus(LED_OFF);
        }
        return count;
    }   
    return count;

}


//字符设备操作集合
static struct file_operations dtsLedF = {
    .owner	= THIS_MODULE,
    .open = LED_open,
    .read = LED_read,
    .write = LED_write,
    .release = LED_release,
};



/*
3 *CCM_CCGR1 0x020C406C
4 *IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04 0x020E006C
5 *IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04 0x020E02F8
6 *GPIO1_GD 0x0209C000
7 *GPIO1_GDIR 0x0209C004
8 */

static int __init DtbLEd_init(void)
{

    const char *str;
    int i =0;
    int rec = 0;
    u32 val;
    //祖册字符设备  使用新的方式
    dtsled.major  =0 ;
    if(dtsled.major)
    {
        dtsled.devid = MKDEV(dtsled.major,0);
        register_chrdev_region(dtsled.devid,DTB_LEDCNT,DTB_LEDNAME);
    }
    else 
    {
        alloc_chrdev_region(&dtsled.devid,0,DTB_LEDCNT,DTB_LEDNAME );
        dtsled.major = MAJOR(dtsled.devid);
        dtsled.minjor = MINOR(dtsled.devid);
    }
    printk("DEVid = %d\n",dtsled.major);
    //添加字符设备
    dtsled.cdev.owner = THIS_MODULE;
    cdev_init(&dtsled.cdev,&dtsLedF);
    cdev_add(&dtsled.cdev,dtsled.devid,DTB_LEDCNT);

    //自动创建设备节点 
    dtsled.class = class_create(THIS_MODULE,DTB_LEDNAME);
    dtsled.device = device_create(dtsled.class, NULL, dtsled.devid,NULL,DTB_LEDNAME);    


    //获取节点
    //1.查找节点
    dtsled.nd=of_find_node_by_path("/XYT_LED");
    rec = of_property_read_string(dtsled.nd,"status",&str);
    if(rec >=0)
    {
        printk("status = %s",str);
    }
    
    rec = of_property_read_u32_array(dtsled.nd,"reg",regdate,10);
    if(rec>=0)
    {
        for(i=0; i<10; i++)
        {
            printk("reg date %#x",regdate[i]);
        }
        printk("\n");
    }
    //映射IO口
    IMX6U_CCM_CCR1 = ioremap(regdate[0], regdate[1]);
    SW_MUX = ioremap(regdate[2], regdate[3]);
    SW_PAD = ioremap(regdate[4], regdate[5]);
    GPIO1_DR = ioremap(regdate[6], regdate[7]);
    GPID1_GDIR = ioremap(regdate[8], regdate[9]);
    //初始化IO口
    writel(0xffffffff, IMX6U_CCM_CCR1);
    writel(5, SW_MUX);
    writel(0x10B0, SW_PAD);

    val = readl(GPID1_GDIR);
    val |= 1 << 4;
    writel(val, GPID1_GDIR);

    val = readl(GPIO1_DR);
    val &= ~(1 << 4);
    writel(val, GPIO1_DR);


    return 0;
} 
static void __exit DtbLED_exit(void)
{


    iounmap(IMX6U_CCM_CCR1);
    iounmap(SW_MUX);
    iounmap(SW_PAD);
    iounmap(GPIO1_DR);
    iounmap(GPID1_GDIR);
    cdev_del(&dtsled.cdev);
    unregister_chrdev_region(dtsled.devid,DTB_LEDCNT);   
    device_destroy(dtsled.class,dtsled.devid);
    class_destroy(dtsled.class);
}



module_init(DtbLEd_init);
module_exit(DtbLED_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xyt");


